package com.lnb.redis.utils;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * <p>
 *
 * </p>
 * @author liaoningbo
 * @since 2023/6/7
*/
@Log4j2
@Component
@Configuration
public class RedissonUtils {
    @Resource
    private RedissonClient redissonClient;

    private static RedissonClient redisson;

    @PostConstruct
    public void init() {
        redisson = redissonClient;
    }

    /**
     * 获取锁，获取timeout秒，如果获取不到则放弃
     * 阻塞获取锁的方式，如果当前锁被其他线程持有，则当前线程会一直阻塞等待获取锁，直到获取到锁或者发生超时或中断等情况才会结束等待
     * @param lockName 锁名
     * @param timeout 获取持续时间
     * @return
     */
    public static RLock lock(String lockName, long timeout, TimeUnit timeUnit) {
        RLock lock = redisson.getLock(lockName);
        lock.lock(timeout, timeUnit);
        return lock;
    }

    /**
     * 获取锁，等待waitTime秒，持有timeOut秒，
     * 非阻塞获取锁的方式，在尝试获取锁时不会阻塞当前线程，而是立即返回获取锁的结果，如果获取成功则返回 true，否则返回 false
     * @param lockName 锁名
     * @param waitTime 等待时间
     * @param timeOut 持有时间，超过持有时间自动释放
     * @return
     */
    public static boolean tryLock(String lockName, Long waitTime, Long timeOut, TimeUnit timeUnit) {
        RLock lock = redisson.getLock(lockName);
        try {
            return lock.tryLock(waitTime, timeOut, timeUnit);
        } catch (InterruptedException e) {
            System.out.println("获取锁失败");
            return false;
        }
    }

    /**
     * 获取锁，持有timeOut秒，
     * 非阻塞获取锁的方式，在尝试获取锁时不会阻塞当前线程，而是立即返回获取锁的结果，如果获取成功则返回 true，否则返回 false
     * @param lockName 锁名
     * @param timeOut 持有时间，超过持有时间自动释放
     * @return
     */
    public static boolean tryLock(String lockName, Long timeOut, TimeUnit timeUnit) {
        RLock lock = redisson.getLock(lockName);
        try {
            return lock.tryLock(-1, timeOut, timeUnit);
        } catch (InterruptedException e) {
            System.out.println("获取锁失败");
            return false;
        }
    }

    /**
     * 释放锁
     * @param lockName
     */
    public static void unlock(String lockName) {
        RLock lock = redisson.getLock(lockName);
        if (lock != null && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /**
     * 释放锁
     * @param lock
     */
    public static void unlock(RLock lock) {
        if (lock != null && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /**
     * <p>
     *    读锁（共享锁）
     * </p>
     * @author liaoningbo
     * @since 2024/6/4
     */
    public static RLock readLock(String lockName, long timeout, TimeUnit timeUnit){
        RReadWriteLock readWriteLock = redisson.getReadWriteLock(lockName);
        RLock rLock = readWriteLock.readLock();
        rLock.lock(timeout, timeUnit);
        return rLock;
    }

    /**
     * <p>
     *    写锁（排他锁）
     * </p>
     * @author liaoningbo
     * @since 2024/6/4
     */
    public static RLock writeLock(String lockName, long timeout, TimeUnit timeUnit){
        RReadWriteLock readWriteLock = redisson.getReadWriteLock(lockName);
        RLock rLock = readWriteLock.writeLock();
        rLock.lock(timeout, timeUnit);
        return rLock;
    }
}
